package util

import (
	"crypto/rand"
	"encoding/hex"
	"github.com/google/uuid"
	"os"
	"path"
	"strconv"
	"time"
)

type MachineIDScheme int

const (
	UUID MachineIDScheme = iota
	HEX32
	HEX64
)

// @description Generate a random UUID
//
// @return string
func genUUID() string {
	return uuid.NewString()
}

// @description Generate a random hex string
//
// @param n int "The length of the hex string"
//
// @return string "The random hex string"
func GenRandomHex(n int) string {
	b := make([]byte, (n+1)/2)
	_, err := rand.Read(b)
	if err != nil {
		panic(err)
	}
	return hex.EncodeToString(b)[:n]
}

// @description Generate a random machine ID
//
// @param scheme MachineIDScheme "The scheme of the machine ID"
//
// Available schemes:
//   - UUID: Generate a UUID
//   - HEX32: Generate a 32-bit hex string
//   - HEX64: Generate a 64-bit hex string
//
// @return string "The machine ID"
func GenMachineID(scheme MachineIDScheme) string {
	switch scheme {
	case UUID:
		return genUUID()
	case HEX32:
		return GenRandomHex(32)
	case HEX64:
		return GenRandomHex(64)
	default:
		return genUUID()
	}
}

// @description Generate a session ID
//
// @return string "The session ID"
func GenSessionID() string {
	return genUUID() + strconv.FormatInt(time.Now().UnixMilli(), 10)
}

// @description Generate a request ID
//
// @return string "The request ID"
func GenRequestID() string {
	return genUUID()
}

// @description mkdir -p for a file path
//
// @param pathname string "The file path"
// @param perm os.FileMode "The file mode"
//
// @return error "The error"
func MkdirAllIfNotExists(pathname string, perm os.FileMode) error {
	dir := path.Dir(pathname)
	if _, err := os.Stat(dir); err != nil {
		if os.IsNotExist(err) {
			if err := os.MkdirAll(dir, perm); err != nil {
				return err
			}
		}
	}
	return nil
}
